package
{
	import fl.controls.Label;
	
	import flare.display.TextSprite;
	
	import flash.display.Sprite;
	import flash.utils.Dictionary;

	public class Axis extends Sprite
	{
		private var axisNames:Array = new Array("field", "salary", "position");
		
		private var dictIndex:Dictionary;
		private var dictIndexRange:Dictionary;
		private var desiredRange:Dictionary;
		private var interval:Dictionary;  // = desiredXRange / (industryIndexRange + 1)
		private var dictBasisVector:Dictionary;
		
		private var w:int = 800;
		private var h:int = 600;
		private var c:Number = Math.cos(Math.PI / 4);
		private var s:Number = Math.sin(Math.PI / 4);
		private var origX:int = 50;
		private var origY:int = 550;
		
		public function Axis(backEnd:BackEnd)
		{
			desiredRange = new Dictionary();
			desiredRange["field"] = 800;
			desiredRange["salary"] =500;
			desiredRange["position"] = 400;
			
			// initialize member variables
			dictIndex = new Dictionary();
			dictIndexRange = new Dictionary();
			interval = new Dictionary();
			dictBasisVector = new Dictionary();
			dictBasisVector["position"] = new Array(0, 0, 1);
			dictBasisVector["field"] = new Array(1, 0, 0);
			dictBasisVector["salary"] = new Array(0, 1, 0);
			
			// set value for each field name
			for each (var name:String in axisNames) {
				
				// build index
				dictIndex[name] = new Dictionary();
				buildOneAxis(dictIndex[name], backEnd.getAll(name));
				
				// compute index range
				dictIndexRange[name] = backEnd.getAll(name).length;
				
				// compute interval on this axis
				interval[name] = desiredRange[name] / (dictIndexRange[name] + 1);
			}
			
			// draw axis
			drawCareerSpace();
		}
		
		private function drawCareerSpace():void {
			var coordOrig:Array = new Array(origX, origY);
			// draw x axis for industry
			var coord2dXAxis:Array = projectTransform(
				new Array(dictIndexRange["field"] * interval["field"], 0, 0));
			drawAxis(coordOrig, coord2dXAxis, "field");
			
			// draw y axis for salary
			var coord2dYAxis:Array = projectTransform(
				new Array(0, dictIndexRange["salary"] * interval["salary"], 0));
			drawAxis(coordOrig, coord2dYAxis, "salary");
			
			// draw z axis for position
			var coord2dZAxis:Array = projectTransform(
				new Array(0, 0, dictIndexRange["position"] * interval["position"]));
			drawAxis(coordOrig, coord2dZAxis, "position");
		}
		
		private function drawAxis(coordOrig:Array, coordEnd:Array, axisName:String):void {
			// line style for axis
			graphics.lineStyle(3, 0xFFFFFF);
			
			// draw axis line
			graphics.moveTo(coordOrig[0], coordOrig[1]);
			graphics.lineTo(coordEnd[0], coordEnd[1]);
			
			// label this axis
			var label:TextSprite = new TextSprite();
			label.text = axisName.toUpperCase();
			label.x = coordEnd[0];
			label.y = coordEnd[1];
			label.color = 0xFFFFFF;
			addChild(label);
			
			// label key points along the axis
			for (var i:Object in this.dictIndex[axisName]) {
				// locate in the 3-d space
				var idx:int = dictIndex[axisName][i];
				var coord3d:Array = new Array(0, 0, 0);
				for (var dim:int = 0; dim < 3; dim++) {
					coord3d[dim] = idx * dictBasisVector[axisName][dim] * interval[axisName];
				}
				
				// convert to 2-d
				var coord2d:Array = this.projectTransform(coord3d);
				
				// label text
				var txt:TextSprite = new TextSprite();
				txt.text = i.toString();
				txt.x = coord2d[0];
				txt.y = coord2d[1];
				txt.color = 0xFFFFFF;
				addChild(txt);
				
				// draw dot
				var dot:Sprite = new Sprite();
				dot.x = txt.x;
				dot.y = txt.y;
				dot.graphics.beginFill(0xFFFFFF);
				dot.graphics.drawCircle(0, 0, 4);
				dot.graphics.endFill();
				addChild(dot);
				
				// draw icon
				var icon:Img = new Img(axisName, idx);
				icon.x = txt.x;
				icon.y = txt.y;
				addChild(icon);
				
				// draw longitude and latitude for desired directions
				if (dictBasisVector[axisName][0] > 0) {  // x axis -> z axis
					dot.graphics.beginFill(0xFFFFFF);
					dot.graphics.lineStyle(1, 0xFFFFFF);
					dot.graphics.lineTo(x + 200, y - 200);
					dot.graphics.endFill();
				}
				else if (dictBasisVector[axisName][2] > 0) { // z axis -> x & y axis
					dot.graphics.beginFill(0xFFFFFF);
					dot.graphics.lineStyle(1, 0xFFFFFF);
					dot.graphics.moveTo(x, y);
					dot.graphics.lineTo(x + 500, y);
					dot.graphics.moveTo(x, y);
					dot.graphics.lineTo(x, y - 400);
					dot.graphics.endFill();
				}
				else {  // y axis -> z axis
					dot.graphics.beginFill(0xFFFFFF);
					dot.graphics.lineStyle(1, 0xFFFFFF);
					dot.graphics.lineTo(x + 200, y - 200);
					dot.graphics.endFill();
				}
			}
		}
		
		public function getXY(job:Job):Array {
			var x:int = getIndex("field", job.getField()) * interval["field"];
			var y:int = getIndex("salary", job.getSalary()) * interval["salary"];
			var z:int = getIndex("position", job.getPosition()) * interval["position"];
			
			return projectTransform(new Array(x, y, z));
		}
		
		private function projectTransform(coord3d:Array):Array {
			// x : industry
			// y : salary
			// z : position
			var x:Number = coord3d[0];
			var y:Number = coord3d[1];
			var z:Number = coord3d[2];
			var coord2d:Array =
				new Array(
					origX + x + z * c,
					origY - y - z * s);
			return coord2d;
		}
		
		public function getIndexRange(axisName:String):int {
			return this.dictIndexRange[axisName];
		}
		
		public function getIndex(field:String, pos:String):int {
			return this.dictIndex[field][pos];
		}
		
		private function buildOneAxis(dict:Dictionary, array:Array):void {
			var i:int = 0;
			for (i = 0; i < array.length; i++) {
				dict[array[i]] = i;
			}
		}
	}
}